package com.qf.realm;

import com.qf.pojo.SysUsers;
import com.qf.service.UserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Set;

/**
 * 自定义Realm类
 * 1.获取数据库中的用户名密码：根据用户名到mysql数据库的用户表中查询数据库的用户名和密码，交给SecurityManager核心对象
 * 2.授权：如果用户名密码正确，赋予用户对应的角色和权限。
 * @author fy
 * @version V1.0
 * @Project workspace
 * @Package com.qf.realm
 * @Description:
 * @Date 2022/6/18 23:08
 */
public class MyUserRealm extends AuthorizingRealm {
    @Autowired
    private UserService userService;
    /**
     * 授权方法，用户名密码校验成功后自动执行这个方法对用户进行授权，为用户赋予角色和权限
     * @param principalCollection shiro框架中在session会话里存储的当前登录用户对象
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("=======自定义Realm类，doGetAuthorizationInfo方法，授权：根据用户名获取用户的角色权限赋予这个用户======");
        //1.获取认证的时候shiro框架中session存储的用户对象
        SysUsers user = (SysUsers) principalCollection.getPrimaryPrincipal();
        //2.根据用户id，到数据库角色表中获取用户的角色信息
        Set<String> roleSet = userService.findRoleByUid(user.getId());
        //3.根据用户id，到数据库权限表或者菜单表中获取用户的权限信息
        Set<String> permSet = userService.findPermByUid(user.getId());
        //4.封装shiro规定的角色权限对象
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();

        //5.将角色数据赋予shiro的权限对象
        authorizationInfo.setRoles(roleSet);
        //6.将权限数据赋予shiro的权限对象
        authorizationInfo.setStringPermissions(permSet);
        //7.返回shiro的权限对象给SecurityManager核心对象
        return authorizationInfo;
    }

    /**
     * 认证方法：从mysql中，根据用户名，获取user表中的用户对象，交给shiro框架的SecurityManager核心管理
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("=======自定义Realm类，doGetAuthenticationInfo方法，登录认证，判断用户名密码========");
        //1.获取用户在登录页面中输入的用户名字
        String username = (String)token.getPrincipal();
        //2.获取用户在登录页面中输入的密码,shiro规定密码必须转换成char类型数组，在转换成S听字符串
        String password = new String((char[])token.getCredentials());
        //3.根据用户名到数据库用户表中获取用户对象
        SysUsers user = userService.findUserByName(username);

        //4.如果用户对象获取不到，抛异常，用户不存在
        if (user==null){
            throw new UnknownAccountException("用户不存在");
        }
        //5.如果用户对象获取到，对比密码是否正确
        if (!password.equals(user.getPassword())){
            //6.如果密码部队抛异常，密码错误
            throw new IncorrectCredentialsException("密码错误");
        }

        //7.如果密码正确，封装返回的用户对象给shiro框架的SecurotyManager核心
        //第一参数：用户对象，第二参数：用户密码，第三参数：当前自定义Realm对象名称
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, this.getName());
        return info;
    }
}
